home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / ixemul-complete / ixemul / static / localtime.c < prev    next >
C/C++ Source or Header  |  1996-05-08  |  39KB  |  1,615 lines

  1. #ifndef lint
  2. #ifndef NOID
  3. static char    elsieid[] = "@(#)localtime.c    7.56";
  4. #endif /* !defined NOID */
  5. #endif /* !defined lint */
  6.  
  7. /*
  8. ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
  9. ** POSIX-style TZ environment variable handling from Guy Harris
  10. ** (guy@auspex.com).
  11. */
  12.  
  13. /*LINTLIBRARY*/
  14.  
  15. #include "private.h"
  16. #include "tzfile.h"
  17. #include "fcntl.h"
  18.  
  19. /*
  20. ** SunOS 4.1.1 headers lack O_BINARY.
  21. */
  22.  
  23. #ifdef O_BINARY
  24. #define OPEN_MODE    (O_RDONLY | O_BINARY)
  25. #endif /* defined O_BINARY */
  26. #ifndef O_BINARY
  27. #define OPEN_MODE    O_RDONLY
  28. #endif /* !defined O_BINARY */
  29.  
  30. #ifndef WILDABBR
  31. /*
  32. ** Someone might make incorrect use of a time zone abbreviation:
  33. **    1.    They might reference tzname[0] before calling tzset (explicitly
  34. **        or implicitly).
  35. **    2.    They might reference tzname[1] before calling tzset (explicitly
  36. **        or implicitly).
  37. **    3.    They might reference tzname[1] after setting to a time zone
  38. **        in which Daylight Saving Time is never observed.
  39. **    4.    They might reference tzname[0] after setting to a time zone
  40. **        in which Standard Time is never observed.
  41. **    5.    They might reference tm.TM_ZONE after calling offtime.
  42. ** What's best to do in the above cases is open to debate;
  43. ** for now, we just set things up so that in any of the five cases
  44. ** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
  45. ** string "tzname[0] used before set", and similarly for the other cases.
  46. ** And another:  initialize tzname[0] to "ERA", with an explanation in the
  47. ** manual page of what this "time zone abbreviation" means (doing this so
  48. ** that tzname[0] has the "normal" length of three characters).
  49. */
  50. #define WILDABBR    "   "
  51. #endif /* !defined WILDABBR */
  52.  
  53. static char        wildabbr[] = "WILDABBR";
  54.  
  55. static const char    gmt[] = "GMT";
  56.  
  57. struct ttinfo {                /* time type information */
  58.     long        tt_gmtoff;    /* GMT offset in seconds */
  59.     int        tt_isdst;    /* used to set tm_isdst */
  60.     int        tt_abbrind;    /* abbreviation list index */
  61.     int        tt_ttisstd;    /* TRUE if transition is std time */
  62.     int        tt_ttisgmt;    /* TRUE if transition is GMT */
  63. };
  64.  
  65. struct lsinfo {                /* leap second information */
  66.     time_t        ls_trans;    /* transition time */
  67.     long        ls_corr;    /* correction to apply */
  68. };
  69.  
  70. #define BIGGEST(a, b)    (((a) > (b)) ? (a) : (b))
  71.  
  72. #ifdef TZNAME_MAX
  73. #define MY_TZNAME_MAX    TZNAME_MAX
  74. #endif /* defined TZNAME_MAX */
  75. #ifndef TZNAME_MAX
  76. #define MY_TZNAME_MAX    255
  77. #endif /* !defined TZNAME_MAX */
  78.  
  79. struct state {
  80.     int        leapcnt;
  81.     int        timecnt;
  82.     int        typecnt;
  83.     int        charcnt;
  84.     time_t        ats[TZ_MAX_TIMES];
  85.     unsigned char    types[TZ_MAX_TIMES];
  86.     struct ttinfo    ttis[TZ_MAX_TYPES];
  87.     char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
  88.                 (2 * (MY_TZNAME_MAX + 1)))];
  89.     struct lsinfo    lsis[TZ_MAX_LEAPS];
  90. };
  91.  
  92. struct rule {
  93.     int        r_type;        /* type of rule--see below */
  94.     int        r_day;        /* day number of rule */
  95.     int        r_week;        /* week number of rule */
  96.     int        r_mon;        /* month number of rule */
  97.     long        r_time;        /* transition time of rule */
  98. };
  99.  
  100. #define JULIAN_DAY        0    /* Jn - Julian day */
  101. #define DAY_OF_YEAR        1    /* n - day of year */
  102. #define MONTH_NTH_DAY_OF_WEEK    2    /* Mm.n.d - month, week, day of week */
  103.  
  104. /*
  105. ** Prototypes for static functions.
  106. */
  107.  
  108. static long        detzcode P((const char * codep));
  109. static const char *    getzname P((const char * strp));
  110. static const char *    getnum P((const char * strp, int * nump, int min,
  111.                 int max));
  112. static const char *    getsecs P((const char * strp, long * secsp));
  113. static const char *    getoffset P((const char * strp, long * offsetp));
  114. static const char *    getrule P((const char * strp, struct rule * rulep));
  115. static void        gmtload P((struct state * sp));
  116. static void        gmtsub P((const time_t * timep, long offset,
  117.                 struct tm * tmp));
  118. static void        localsub P((const time_t * timep, long offset,
  119.                 struct tm * tmp));
  120. static int        increment_overflow P((int * number, int delta));
  121. static int        normalize_overflow P((int * tensptr, int * unitsptr,
  122.                 int base));
  123. static void        settzname P((void));
  124. static time_t        time1 P((struct tm * tmp,
  125.                 void(*funcp) P((const time_t *,
  126.                 long, struct tm *)),
  127.                 long offset));
  128. static time_t        time2 P((struct tm *tmp,
  129.                 void(*funcp) P((const time_t *,
  130.                 long, struct tm*)),
  131.                 long offset, int * okayp));
  132. static void        timesub P((const time_t * timep, long offset,
  133.                 const struct state * sp, struct tm * tmp));
  134. static int        tmcomp P((const struct tm * atmp,
  135.                 const struct tm * btmp));
  136. static time_t        transtime P((time_t janfirst, int year,
  137.                 const struct rule * rulep, long offset));
  138. static int        tzload P((const char * name, struct state * sp));
  139. static int        tzparse P((const char * name, struct state * sp,
  140.                 int lastditch));
  141.  
  142. #ifdef ALL_STATE
  143. static struct state *    lclptr;
  144. static struct state *    gmtptr;
  145. #endif /* defined ALL_STATE */
  146.  
  147. #ifndef ALL_STATE
  148. static struct state    lclmem;
  149. static struct state    gmtmem;
  150. #define lclptr        (&lclmem)
  151. #define gmtptr        (&gmtmem)
  152. #endif /* State Farm */
  153.  
  154. #ifndef TZ_STRLEN_MAX
  155. #define TZ_STRLEN_MAX 255
  156. #endif /* !defined TZ_STRLEN_MAX */
  157.  
  158. static char        lcl_TZname[TZ_STRLEN_MAX + 1];
  159. static int        lcl_is_set;
  160. static int        gmt_is_set;
  161.  
  162. char *            tzname[2] = {
  163.     wildabbr,
  164.     wildabbr
  165. };
  166.  
  167. /*
  168. ** Section 4.12.3 of X3.159-1989 requires that
  169. **    Except for the strftime function, these functions [asctime,
  170. **    ctime, gmtime, localtime] return values in one of two static
  171. **    objects: a broken-down time structure and an array of char.
  172. ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
  173. */
  174.  
  175. static struct tm    tm;
  176.  
  177. #ifdef USG_COMPAT
  178. time_t            timezone = 0;
  179. int            daylight = 0;
  180. #endif /* defined USG_COMPAT */
  181.  
  182. #ifdef ALTZONE
  183. time_t            altzone = 0;
  184. #endif /* defined ALTZONE */
  185.  
  186. /*
  187. ** Section 4.9.1 of the C standard says that
  188. ** "FILENAME_MAX expands to an integral constant expression
  189. ** that is the sie needed for an array of char large enough
  190. ** to hold the longest file name string that the implementation
  191. ** guarantees can be opened."
  192. */
  193. static char        fullname[FILENAME_MAX + 1];
  194.  
  195. static char        buf[sizeof (struct state) + sizeof (struct tzhead)];
  196.  
  197. static long
  198. detzcode(codep)
  199. const char * const    codep;
  200. {
  201.     register long    result;
  202.     register int    i;
  203.  
  204.     result = (codep[0] & 0x80) ? ~0L : 0L;
  205.     for (i = 0; i < 4; ++i)
  206.         result = (result << 8) | (codep[i] & 0xff);
  207.     return result;
  208. }
  209.  
  210. static void
  211. settzname P((void))
  212. {
  213.     register struct state * const    sp = lclptr;
  214.     register int            i;
  215.  
  216.     tzname[0] = wildabbr;
  217.     tzname[1] = wildabbr;
  218. #ifdef USG_COMPAT
  219.     daylight = 0;
  220.     timezone = 0;
  221. #endif /* defined USG_COMPAT */
  222. #ifdef ALTZONE
  223.     altzone = 0;
  224. #endif /* defined ALTZONE */
  225. #ifdef ALL_STATE
  226.     if (sp == NULL) {
  227.         tzname[0] = tzname[1] = gmt;
  228.         return;
  229.     }
  230. #endif /* defined ALL_STATE */
  231.     for (i = 0; i < sp->typecnt; ++i) {
  232.         register const struct ttinfo * const    ttisp = &sp->ttis[i];
  233.  
  234.         tzname[ttisp->tt_isdst] =
  235.             &sp->chars[ttisp->tt_abbrind];
  236. #ifdef USG_COMPAT
  237.         if (ttisp->tt_isdst)
  238.             daylight = 1;
  239.         if (i == 0 || !ttisp->tt_isdst)
  240.             timezone = -(ttisp->tt_gmtoff);
  241. #endif /* defined USG_COMPAT */
  242. #ifdef ALTZONE
  243.         if (i == 0 || ttisp->tt_isdst)
  244.             altzone = -(ttisp->tt_gmtoff);
  245. #endif /* defined ALTZONE */
  246.     }
  247.     /*
  248.     ** And to get the latest zone names into tzname. . .
  249.     */
  250.     for (i = 0; i < sp->timecnt; ++i) {
  251.         register const struct ttinfo * const    ttisp =
  252.                             &sp->ttis[
  253.                                 sp->types[i]];
  254.  
  255.         tzname[ttisp->tt_isdst] =
  256.             &sp->chars[ttisp->tt_abbrind];
  257.     }
  258. }
  259.  
  260. static int
  261. tzload(name, sp)
  262. register const char *        name;
  263. register struct state * const    sp;
  264. {
  265.     register const char *    p;
  266.     register int        i;
  267.     register int        fid;
  268.  
  269.     if (name == NULL && (name = TZDEFAULT) == NULL)
  270.         return -1;
  271.     {
  272.         register int    doaccess;
  273.  
  274.         if (name[0] == ':')
  275.             ++name;
  276.         doaccess = name[0] == '/';
  277.         if (!doaccess) {
  278.             if ((p = TZDIR) == NULL)
  279.                 return -1;
  280.             if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  281.                 return -1;
  282.             (void) strcpy(fullname, p);
  283.             (void) strcat(fullname, "/");
  284.             (void) strcat(fullname, name);
  285.             /*
  286.             ** Set doaccess if '.' (as in "../") shows up in name.
  287.             */
  288.             if (strchr(name, '.') != NULL)
  289.                 doaccess = TRUE;
  290.             name = fullname;
  291.         }
  292.         if (doaccess && access(name, R_OK) != 0)
  293.             return -1;
  294.         if ((fid = open(name, OPEN_MODE)) == -1)
  295.             return -1;
  296.     }
  297.     {
  298.         struct tzhead *    tzhp;
  299.         int        ttisstdcnt;
  300.         int        ttisgmtcnt;
  301.  
  302.         i = read(fid, buf, sizeof buf);
  303.         if (close(fid) != 0)
  304.             return -1;
  305.         p = buf;
  306.         p += sizeof tzhp->tzh_reserved;
  307.         ttisstdcnt = (int) detzcode(p);
  308.         p += 4;
  309.         ttisgmtcnt = (int) detzcode(p);
  310.         p += 4;
  311.         sp->leapcnt = (int) detzcode(p);
  312.         p += 4;
  313.         sp->timecnt = (int) detzcode(p);
  314.         p += 4;
  315.         sp->typecnt = (int) detzcode(p);
  316.         p += 4;
  317.         sp->charcnt = (int) detzcode(p);
  318.         p += 4;
  319.         if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
  320.             sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
  321.             sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
  322.             sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
  323.             (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
  324.             (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
  325.                 return -1;
  326.         if (i - (p - buf) < sp->timecnt * 4 +    /* ats */
  327.             sp->timecnt +            /* types */
  328.             sp->typecnt * (4 + 2) +        /* ttinfos */
  329.             sp->charcnt +            /* chars */
  330.             sp->leapcnt * (4 + 4) +        /* lsinfos */
  331.             ttisstdcnt +            /* ttisstds */
  332.             ttisgmtcnt)            /* ttisgmts */
  333.                 return -1;
  334.         for (i = 0; i < sp->timecnt; ++i) {
  335.             sp->ats[i] = detzcode(p);
  336.             p += 4;
  337.         }
  338.         for (i = 0; i < sp->timecnt; ++i) {
  339.             sp->types[i] = (unsigned char) *p++;
  340.             if (sp->types[i] >= sp->typecnt)
  341.                 return -1;
  342.         }
  343.         for (i = 0; i < sp->typecnt; ++i) {
  344.             register struct ttinfo *    ttisp;
  345.  
  346.             ttisp = &sp->ttis[i];
  347.             ttisp->tt_gmtoff = detzcode(p);
  348.             p += 4;
  349.             ttisp->tt_isdst = (unsigned char) *p++;
  350.             if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
  351.                 return -1;
  352.             ttisp->tt_abbrind = (unsigned char) *p++;
  353.             if (ttisp->tt_abbrind < 0 ||
  354.                 ttisp->tt_abbrind > sp->charcnt)
  355.                     return -1;
  356.         }
  357.         for (i = 0; i < sp->charcnt; ++i)
  358.             sp->chars[i] = *p++;
  359.         sp->chars[i] = '\0';    /* ensure '\0' at end */
  360.         for (i = 0; i < sp->leapcnt; ++i) {
  361.             register struct lsinfo *    lsisp;
  362.  
  363.             lsisp = &sp->lsis[i];
  364.             lsisp->ls_trans = detzcode(p);
  365.             p += 4;
  366.             lsisp->ls_corr = detzcode(p);
  367.             p += 4;
  368.         }
  369.         for (i = 0; i < sp->typecnt; ++i) {
  370.             register struct ttinfo *    ttisp;
  371.  
  372.             ttisp = &sp->ttis[i];
  373.             if (ttisstdcnt == 0)
  374.                 ttisp->tt_ttisstd = FALSE;
  375.             else {
  376.                 ttisp->tt_ttisstd = *p++;
  377.                 if (ttisp->tt_ttisstd != TRUE &&
  378.                     ttisp->tt_ttisstd != FALSE)
  379.                         return -1;
  380.             }
  381.         }
  382.         for (i = 0; i < sp->typecnt; ++i) {
  383.             register struct ttinfo *    ttisp;
  384.  
  385.             ttisp = &sp->ttis[i];
  386.             if (ttisgmtcnt == 0)
  387.                 ttisp->tt_ttisgmt = FALSE;
  388.             else {
  389.                 ttisp->tt_ttisgmt = *p++;
  390.                 if (ttisp->tt_ttisgmt != TRUE &&
  391.                     ttisp->tt_ttisgmt != FALSE)
  392.                         return -1;
  393.             }
  394.         }
  395.     }
  396.     return 0;
  397. }
  398.  
  399. static const int    mon_lengths[2][MONSPERYEAR] = {
  400.     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  401.     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  402. };
  403.  
  404. static const int    year_lengths[2] = {
  405.     DAYSPERNYEAR, DAYSPERLYEAR
  406. };
  407.  
  408. /*
  409. ** Given a pointer into a time zone string, scan until a character that is not
  410. ** a valid character in a zone name is found.  Return a pointer to that
  411. ** character.
  412. */
  413.  
  414. static const char *
  415. getzname(strp)
  416. register const char *    strp;
  417. {
  418.     register char    c;
  419.  
  420.     while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
  421.         c != '+')
  422.             ++strp;
  423.     return strp;
  424. }
  425.  
  426. /*
  427. ** Given a pointer into a time zone string, extract a number from that string.
  428. ** Check that the number is within a specified range; if it is not, return
  429. ** NULL.
  430. ** Otherwise, return a pointer to the first character not part of the number.
  431. */
  432.  
  433. static const char *
  434. getnum(strp, nump, min, max)
  435. register const char *    strp;
  436. int * const        nump;
  437. const int        min;
  438. const int        max;
  439. {
  440.     register char    c;
  441.     register int    num;
  442.  
  443.     if (strp == NULL || !is_digit(c = *strp))
  444.         return NULL;
  445.     num = 0;
  446.     do {
  447.         num = num * 10 + (c - '0');
  448.         if (num > max)
  449.             return NULL;    /* illegal value */
  450.         c = *++strp;
  451.     } while (is_digit(c));
  452.     if (num < min)
  453.         return NULL;        /* illegal value */
  454.     *nump = num;
  455.     return strp;
  456. }
  457.  
  458. /*
  459. ** Given a pointer into a time zone string, extract a number of seconds,
  460. ** in hh[:mm[:ss]] form, from the string.
  461. ** If any error occurs, return NULL.
  462. ** Otherwise, return a pointer to the first character not part of the number
  463. ** of seconds.
  464. */
  465.  
  466. static const char *
  467. getsecs(strp, secsp)
  468. register const char *    strp;
  469. long * const        secsp;
  470. {
  471.     int    num;
  472.  
  473.     /*
  474.     ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
  475.     ** "M10.4.6/26", which does not conform to Posix,
  476.     ** but which specifies the equivalent of
  477.     ** ``02:00 on the first Sunday on or after 23 Oct''.
  478.     */
  479.     strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
  480.     if (strp == NULL)
  481.         return NULL;
  482.     *secsp = num * (long) SECSPERHOUR;
  483.     if (*strp == ':') {
  484.         ++strp;
  485.         strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
  486.         if (strp == NULL)
  487.             return NULL;
  488.         *secsp += num * SECSPERMIN;
  489.         if (*strp == ':') {
  490.             ++strp;
  491.             /* `SECSPERMIN' allows for leap seconds.  */
  492.             strp = getnum(strp, &num, 0, SECSPERMIN);
  493.             if (strp == NULL)
  494.                 return NULL;
  495.             *secsp += num;
  496.         }
  497.     }
  498.     return strp;
  499. }
  500.  
  501. /*
  502. ** Given a pointer into a time zone string, extract an offset, in
  503. ** [+-]hh[:mm[:ss]] form, from the string.
  504. ** If any error occurs, return NULL.
  505. ** Otherwise, return a pointer to the first character not part of the time.
  506. */
  507.  
  508. static const char *
  509. getoffset(strp, offsetp)
  510. register const char *    strp;
  511. long * const        offsetp;
  512. {
  513.     register int    neg = 0;
  514.  
  515.     if (*strp == '-') {
  516.         neg = 1;
  517.         ++strp;
  518.     } else if (*strp == '+')
  519.         ++strp;
  520.     strp = getsecs(strp, offsetp);
  521.     if (strp == NULL)
  522.         return NULL;        /* illegal time */
  523.     if (neg)
  524.         *offsetp = -*offsetp;
  525.     return strp;
  526. }
  527.  
  528. /*
  529. ** Given a pointer into a time zone string, extract a rule in the form
  530. ** date[/time].  See POSIX section 8 for the format of "date" and "time".
  531. ** If a valid rule is not found, return NULL.
  532. ** Otherwise, return a pointer to the first character not part of the rule.
  533. */
  534.  
  535. static const char *
  536. getrule(strp, rulep)
  537. const char *            strp;
  538. register struct rule * const    rulep;
  539. {
  540.     if (*strp == 'J') {
  541.         /*
  542.         ** Julian day.
  543.         */
  544.         rulep->r_type = JULIAN_DAY;
  545.         ++strp;
  546.         strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
  547.     } else if (*strp == 'M') {
  548.         /*
  549.         ** Month, week, day.
  550.         */
  551.         rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
  552.         ++strp;
  553.         strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
  554.         if (strp == NULL)
  555.             return NULL;
  556.         if (*strp++ != '.')
  557.             return NULL;
  558.         strp = getnum(strp, &rulep->r_week, 1, 5);
  559.         if (strp == NULL)
  560.             return NULL;
  561.         if (*strp++ != '.')
  562.             return NULL;
  563.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
  564.     } else if (is_digit(*strp)) {
  565.         /*
  566.         ** Day of year.
  567.         */
  568.         rulep->r_type = DAY_OF_YEAR;
  569.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
  570.     } else    return NULL;        /* invalid format */
  571.     if (strp == NULL)
  572.         return NULL;
  573.     if (*strp == '/') {
  574.         /*
  575.         ** Time specified.
  576.         */
  577.         ++strp;
  578.         strp = getsecs(strp, &rulep->r_time);
  579.     } else    rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
  580.     return strp;
  581. }
  582.  
  583. /*
  584. ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
  585. ** year, a rule, and the offset from GMT at the time that rule takes effect,
  586. ** calculate the Epoch-relative time that rule takes effect.
  587. */
  588.  
  589. static time_t
  590. transtime(janfirst, year, rulep, offset)
  591. const time_t                janfirst;
  592. const int                year;
  593. register const struct rule * const    rulep;
  594. const long                offset;
  595. {
  596.     register int    leapyear;
  597.     register time_t    value;
  598.     register int    i;
  599.     int        d, m1, yy0, yy1, yy2, dow;
  600.  
  601.     INITIALIZE(value);
  602.     leapyear = isleap(year);
  603.     switch (rulep->r_type) {
  604.  
  605.     case JULIAN_DAY:
  606.         /*
  607.         ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
  608.         ** years.
  609.         ** In non-leap years, or if the day number is 59 or less, just
  610.         ** add SECSPERDAY times the day number-1 to the time of
  611.         ** January 1, midnight, to get the day.
  612.         */
  613.         value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
  614.         if (leapyear && rulep->r_day >= 60)
  615.             value += SECSPERDAY;
  616.         break;
  617.  
  618.     case DAY_OF_YEAR:
  619.         /*
  620.         ** n - day of year.
  621.         ** Just add SECSPERDAY times the day number to the time of
  622.         ** January 1, midnight, to get the day.
  623.         */
  624.         value = janfirst + rulep->r_day * SECSPERDAY;
  625.         break;
  626.  
  627.     case MONTH_NTH_DAY_OF_WEEK:
  628.         /*
  629.         ** Mm.n.d - nth "dth day" of month m.
  630.         */
  631.         value = janfirst;
  632.         for (i = 0; i < rulep->r_mon - 1; ++i)
  633.             value += mon_lengths[leapyear][i] * SECSPERDAY;
  634.  
  635.         /*
  636.         ** Use Zeller's Congruence to get day-of-week of first day of
  637.         ** month.
  638.         */
  639.         m1 = (rulep->r_mon + 9) % 12 + 1;
  640.         yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
  641.         yy1 = yy0 / 100;
  642.         yy2 = yy0 % 100;
  643.         dow = ((26 * m1 - 2) / 10 +
  644.             1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
  645.         if (dow < 0)
  646.             dow += DAYSPERWEEK;
  647.  
  648.         /*
  649.         ** "dow" is the day-of-week of the first day of the month.  Get
  650.         ** the day-of-month (zero-origin) of the first "dow" day of the
  651.         ** month.
  652.         */
  653.         d = rulep->r_day - dow;
  654.         if (d < 0)
  655.             d += DAYSPERWEEK;
  656.         for (i = 1; i < rulep->r_week; ++i) {
  657.             if (d + DAYSPERWEEK >=
  658.                 mon_lengths[leapyear][rulep->r_mon - 1])
  659.                     break;
  660.             d += DAYSPERWEEK;
  661.         }
  662.  
  663.         /*
  664.         ** "d" is the day-of-month (zero-origin) of the day we want.
  665.         */
  666.         value += d * SECSPERDAY;
  667.         break;
  668.     }
  669.  
  670.     /*
  671.     ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
  672.     ** question.  To get the Epoch-relative time of the specified local
  673.     ** time on that day, add the transition time and the current offset
  674.     ** from GMT.
  675.     */
  676.     return value + rulep->r_time + offset;
  677. }
  678.  
  679. /*
  680. ** Given a POSIX section 8-style TZ string, fill in the rule tables as
  681. ** appropriate.
  682. */
  683.  
  684. static int
  685. tzparse(name, sp, lastditch)
  686. const char *            name;
  687. register struct state * const    sp;
  688. const int            lastditch;
  689. {
  690.     const char *            stdname;
  691.     const char *            dstname;
  692.     size_t                stdlen;
  693.     size_t                dstlen;
  694.     long                stdoffset;
  695.     long                dstoffset;
  696.     register time_t *        atp;
  697.     register unsigned char *    typep;
  698.     register char *            cp;
  699.     register int            load_result;
  700.  
  701.     INITIALIZE(dstname);
  702.     stdname = name;
  703.     if (lastditch) {
  704.         stdlen = strlen(name);    /* length of standard zone name */
  705.         name += stdlen;
  706.         if (stdlen >= sizeof sp->chars)
  707.             stdlen = (sizeof sp->chars) - 1;
  708.     } else {
  709.         name = getzname(name);
  710.         stdlen = name - stdname;
  711.         if (stdlen < 3)
  712.             return -1;
  713.     }
  714.     if (*name == '\0')
  715.         return -1;    /* was "stdoffset = 0;" */
  716.     else {
  717.         name = getoffset(name, &stdoffset);
  718.         if (name == NULL)
  719.             return -1;
  720.     }
  721.     load_result = tzload(TZDEFRULES, sp);
  722.     if (load_result != 0)
  723.         sp->leapcnt = 0;        /* so, we're off a little */
  724.     if (*name != '\0') {
  725.         dstname = name;
  726.         name = getzname(name);
  727.         dstlen = name - dstname;    /* length of DST zone name */
  728.         if (dstlen < 3)
  729.             return -1;
  730.         if (*name != '\0' && *name != ',' && *name != ';') {
  731.             name = getoffset(name, &dstoffset);
  732.             if (name == NULL)
  733.                 return -1;
  734.         } else    dstoffset = stdoffset - SECSPERHOUR;
  735.         if (*name == ',' || *name == ';') {
  736.             struct rule    start;
  737.             struct rule    end;
  738.             register int    year;
  739.             register time_t    janfirst;
  740.             time_t        starttime;
  741.             time_t        endtime;
  742.  
  743.             ++name;
  744.             if ((name = getrule(name, &start)) == NULL)
  745.                 return -1;
  746.             if (*name++ != ',')
  747.                 return -1;
  748.             if ((name = getrule(name, &end)) == NULL)
  749.                 return -1;
  750.             if (*name != '\0')
  751.                 return -1;
  752.             sp->typecnt = 2;    /* standard time and DST */
  753.             /*
  754.             ** Two transitions per year, from EPOCH_YEAR to 2037.
  755.             */
  756.             sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
  757.             if (sp->timecnt > TZ_MAX_TIMES)
  758.                 return -1;
  759.             sp->ttis[0].tt_gmtoff = -dstoffset;
  760.             sp->ttis[0].tt_isdst = 1;
  761.             sp->ttis[0].tt_abbrind = stdlen + 1;
  762.             sp->ttis[1].tt_gmtoff = -stdoffset;
  763.             sp->ttis[1].tt_isdst = 0;
  764.             sp->ttis[1].tt_abbrind = 0;
  765.             atp = sp->ats;
  766.             typep = sp->types;
  767.             janfirst = 0;
  768.             for (year = EPOCH_YEAR; year <= 2037; ++year) {
  769.                 starttime = transtime(janfirst, year, &start,
  770.                     stdoffset);
  771.                 endtime = transtime(janfirst, year, &end,
  772.                     dstoffset);
  773.                 if (starttime > endtime) {
  774.                     *atp++ = endtime;
  775.                     *typep++ = 1;    /* DST ends */
  776.                     *atp++ = starttime;
  777.                     *typep++ = 0;    /* DST begins */
  778.                 } else {
  779.                     *atp++ = starttime;
  780.                     *typep++ = 0;    /* DST begins */
  781.                     *atp++ = endtime;
  782.                     *typep++ = 1;    /* DST ends */
  783.                 }
  784.                 janfirst += year_lengths[isleap(year)] *
  785.                     SECSPERDAY;
  786.             }
  787.         } else {
  788.             register long    theirstdoffset;
  789.             register long    theirdstoffset;
  790.             register long    theiroffset;
  791.             register int    isdst;
  792.             register int    i;
  793.             register int    j;
  794.  
  795.             if (*name != '\0')
  796.                 return -1;
  797.             if (load_result != 0)
  798.                 return -1;
  799.             /*
  800.             ** Initial values of theirstdoffset and theirdstoffset.
  801.             */
  802.             theirstdoffset = 0;
  803.             for (i = 0; i < sp->timecnt; ++i) {
  804.                 j = sp->types[i];
  805.                 if (!sp->ttis[j].tt_isdst) {
  806.                     theirstdoffset =
  807.                         -sp->ttis[j].tt_gmtoff;
  808.                     break;
  809.                 }
  810.             }
  811.             theirdstoffset = 0;
  812.             for (i = 0; i < sp->timecnt; ++i) {
  813.                 j = sp->types[i];
  814.                 if (sp->ttis[j].tt_isdst) {
  815.                     theirdstoffset =
  816.                         -sp->ttis[j].tt_gmtoff;
  817.                     break;
  818.                 }
  819.             }
  820.             /*
  821.             ** Initially we're assumed to be in standard time.
  822.             */
  823.             isdst = FALSE;
  824.             theiroffset = theirstdoffset;
  825.             /*
  826.             ** Now juggle transition times and types
  827.             ** tracking offsets as you do.
  828.             */
  829.             for (i = 0; i < sp->timecnt; ++i) {
  830.                 j = sp->types[i];
  831.                 sp->types[i] = sp->ttis[j].tt_isdst;
  832.                 if (sp->ttis[j].tt_ttisgmt) {
  833.                     /* No adjustment to transition time */
  834.                 } else {
  835.                     /*
  836.                     ** If summer time is in effect, and the
  837.                     ** transition time was not specified as
  838.                     ** standard time, add the summer time
  839.                     ** offset to the transition time;
  840.                     ** otherwise, add the standard time
  841.                     ** offset to the transition time.
  842.                     */
  843.                     /*
  844.                     ** Transitions from DST to DDST
  845.                     ** will effectively disappear since
  846.                     ** POSIX provides for only one DST
  847.                     ** offset.
  848.                     */
  849.                     if (isdst && !sp->ttis[j].tt_ttisstd) {
  850.                         sp->ats[i] += dstoffset -
  851.                             theirdstoffset;
  852.                     } else {
  853.                         sp->ats[i] += stdoffset -
  854.                             theirstdoffset;
  855.                     }
  856.                 }
  857.                 theiroffset = -sp->ttis[j].tt_gmtoff;
  858.                 if (sp->ttis[j].tt_isdst)
  859.                     theirdstoffset = theiroffset;
  860.                 else    theirstdoffset = theiroffset;
  861.             }
  862.             /*
  863.             ** Finally, fill in ttis.
  864.             ** ttisstd and ttisgmt need not be handled.
  865.             */
  866.             sp->ttis[0].tt_gmtoff = -stdoffset;
  867.             sp->ttis[0].tt_isdst = FALSE;
  868.             sp->ttis[0].tt_abbrind = 0;
  869.             sp->ttis[1].tt_gmtoff = -dstoffset;
  870.             sp->ttis[1].tt_isdst = TRUE;
  871.             sp->ttis[1].tt_abbrind = stdlen + 1;
  872.         }
  873.     } else {
  874.         dstlen = 0;
  875.         sp->typecnt = 1;        /* only standard time */
  876.         sp->timecnt = 0;
  877.         sp->ttis[0].tt_gmtoff = -stdoffset;
  878.         sp->ttis[0].tt_isdst = 0;
  879.         sp->ttis[0].tt_abbrind = 0;
  880.     }
  881.     sp->charcnt = stdlen + 1;
  882.     if (dstlen != 0)
  883.         sp->charcnt += dstlen + 1;
  884.     if (sp->charcnt > sizeof sp->chars)
  885.         return -1;
  886.     cp = sp->chars;
  887.     (void) strncpy(cp, stdname, stdlen);
  888.     cp += stdlen;
  889.     *cp++ = '\0';
  890.     if (dstlen != 0) {
  891.         (void) strncpy(cp, dstname, dstlen);
  892.         *(cp + dstlen) = '\0';
  893.     }
  894.     return 0;
  895. }
  896.  
  897. static void
  898. gmtload(sp)
  899. struct state * const    sp;
  900. {
  901.     if (tzload(gmt, sp) != 0)
  902.         (void) tzparse(gmt, sp, TRUE);
  903. }
  904.  
  905. #if !defined(STD_INSPIRED) && !defined(__amigados__)
  906. /*
  907. ** A non-static declaration of tzsetwall in a system header file
  908. ** may cause a warning about this upcoming static declaration...
  909. */
  910. static
  911. #endif /* !defined STD_INSPIRED */
  912. void
  913. tzsetwall P((void))
  914. {
  915.     if (lcl_is_set < 0)
  916.         return;
  917.     lcl_is_set = -1;
  918.  
  919. #ifdef ALL_STATE
  920.     if (lclptr == NULL) {
  921.         lclptr = (struct state *) malloc(sizeof *lclptr);
  922.         if (lclptr == NULL) {
  923.             settzname();    /* all we can do */
  924.             return;
  925.         }
  926.     }
  927. #endif /* defined ALL_STATE */
  928.     if (tzload((char *) NULL, lclptr) != 0)
  929.         gmtload(lclptr);
  930.     settzname();
  931. }
  932.  
  933. void
  934. tzset P((void))
  935. {
  936.     register const char *    name;
  937.  
  938.     name = getenv("TZ");
  939.     if (name == NULL) {
  940.         tzsetwall();
  941.         return;
  942.     }
  943.  
  944.     if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
  945.         return;
  946.     lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
  947.     if (lcl_is_set)
  948.         (void) strcpy(lcl_TZname, name);
  949.  
  950. #ifdef ALL_STATE
  951.     if (lclptr == NULL) {
  952.         lclptr = (struct state *) malloc(sizeof *lclptr);
  953.         if (lclptr == NULL) {
  954.             settzname();    /* all we can do */
  955.             return;
  956.         }
  957.     }
  958. #endif /* defined ALL_STATE */
  959.     if (*name == '\0') {
  960.         /*
  961.         ** User wants it fast rather than right.
  962.         */
  963.         lclptr->leapcnt = 0;        /* so, we're off a little */
  964.         lclptr->timecnt = 0;
  965.         lclptr->ttis[0].tt_gmtoff = 0;
  966.         lclptr->ttis[0].tt_abbrind = 0;
  967.         (void) strcpy(lclptr->chars, gmt);
  968.     } else if (tzload(name, lclptr) != 0)
  969.         if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
  970.             (void) gmtload(lclptr);
  971.     settzname();
  972. }
  973.  
  974. /*
  975. ** The easy way to behave "as if no library function calls" localtime
  976. ** is to not call it--so we drop its guts into "localsub", which can be
  977. ** freely called.  (And no, the PANS doesn't require the above behavior--
  978. ** but it *is* desirable.)
  979. **
  980. ** The unused offset argument is for the benefit of mktime variants.
  981. */
  982.  
  983. /*ARGSUSED*/
  984. static void
  985. localsub(timep, offset, tmp)
  986. const time_t * const    timep;
  987. const long        offset;
  988. struct tm * const    tmp;
  989. {
  990.     register struct state *        sp;
  991.     register const struct ttinfo *    ttisp;
  992.     register int            i;
  993.     const time_t            t = *timep;
  994.  
  995.     sp = lclptr;
  996. #ifdef ALL_STATE
  997.     if (sp == NULL) {
  998.         gmtsub(timep, offset, tmp);
  999.         return;
  1000.     }
  1001. #endif /* defined ALL_STATE */
  1002.     if (sp->timecnt == 0 || t < sp->ats[0]) {
  1003.         i = 0;
  1004.         while (sp->ttis[i].tt_isdst)
  1005.             if (++i >= sp->typecnt) {
  1006.                 i = 0;
  1007.                 break;
  1008.             }
  1009.     } else {
  1010.         for (i = 1; i < sp->timecnt; ++i)
  1011.             if (t < sp->ats[i])
  1012.                 break;
  1013.         i = sp->types[i - 1];
  1014.     }
  1015.     ttisp = &sp->ttis[i];
  1016.     /*
  1017.     ** To get (wrong) behavior that's compatible with System V Release 2.0
  1018.     ** you'd replace the statement below with
  1019.     **    t += ttisp->tt_gmtoff;
  1020.     **    timesub(&t, 0L, sp, tmp);
  1021.     */
  1022.     timesub(&t, ttisp->tt_gmtoff, sp, tmp);
  1023.     tmp->tm_isdst = ttisp->tt_isdst;
  1024.     tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
  1025. #ifdef TM_ZONE
  1026.     tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
  1027. #endif /* defined TM_ZONE */
  1028. }
  1029.  
  1030. struct tm *
  1031. localtime(timep)
  1032. const time_t * const    timep;
  1033. {
  1034.     tzset();
  1035.     localsub(timep, 0L, &tm);
  1036.     return &tm;
  1037. }
  1038.  
  1039. /*
  1040. ** gmtsub is to gmtime as localsub is to localtime.
  1041. */
  1042.  
  1043. static void
  1044. gmtsub(timep, offset, tmp)
  1045. const time_t * const    timep;
  1046. const long        offset;
  1047. struct tm * const    tmp;
  1048. {
  1049.     if (!gmt_is_set) {
  1050.         gmt_is_set = TRUE;
  1051. #ifdef ALL_STATE
  1052.         gmtptr = (struct state *) malloc(sizeof *gmtptr);
  1053.         if (gmtptr != NULL)
  1054. #endif /* defined ALL_STATE */
  1055.             gmtload(gmtptr);
  1056.     }
  1057.     timesub(timep, offset, gmtptr, tmp);
  1058. #ifdef TM_ZONE
  1059.     /*
  1060.     ** Could get fancy here and deliver something such as
  1061.     ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
  1062.     ** but this is no time for a treasure hunt.
  1063.     */
  1064.     if (offset != 0)
  1065.         tmp->TM_ZONE = wildabbr;
  1066.     else {
  1067. #ifdef ALL_STATE
  1068.         if (gmtptr == NULL)
  1069.             tmp->TM_ZONE = gmt;
  1070.         else    tmp->TM_ZONE = gmtptr->chars;
  1071. #endif /* defined ALL_STATE */
  1072. #ifndef ALL_STATE
  1073.         tmp->TM_ZONE = gmtptr->chars;
  1074. #endif /* State Farm */
  1075.     }
  1076. #endif /* defined TM_ZONE */
  1077. }
  1078.  
  1079. struct tm *
  1080. gmtime(timep)
  1081. const time_t * const    timep;
  1082. {
  1083.     gmtsub(timep, 0L, &tm);
  1084.     return &tm;
  1085. }
  1086.  
  1087. #ifdef STD_INSPIRED
  1088.  
  1089. struct tm *
  1090. offtime(timep, offset)
  1091. const time_t * const    timep;
  1092. const long        offset;
  1093. {
  1094.     gmtsub(timep, offset, &tm);
  1095.     return &tm;
  1096. }
  1097.  
  1098. #endif /* defined STD_INSPIRED */
  1099.  
  1100. static void
  1101. timesub(timep, offset, sp, tmp)
  1102. const time_t * const            timep;
  1103. const long                offset;
  1104. register const struct state * const    sp;
  1105. register struct tm * const        tmp;
  1106. {
  1107.     register const struct lsinfo *    lp;
  1108.     register long            days;
  1109.     register long            rem;
  1110.     register int            y;
  1111.     register int            yleap;
  1112.     register const int *        ip;
  1113.     register long            corr;
  1114.     register int            hit;
  1115.     register int            i;
  1116.  
  1117.     corr = 0;
  1118.     hit = 0;
  1119. #ifdef ALL_STATE
  1120.     i = (sp == NULL) ? 0 : sp->leapcnt;
  1121. #endif /* defined ALL_STATE */
  1122. #ifndef ALL_STATE
  1123.     i = sp->leapcnt;
  1124. #endif /* State Farm */
  1125.     while (--i >= 0) {
  1126.         lp = &sp->lsis[i];
  1127.         if (*timep >= lp->ls_trans) {
  1128.             if (*timep == lp->ls_trans) {
  1129.                 hit = ((i == 0 && lp->ls_corr > 0) ||
  1130.                     lp->ls_corr > sp->lsis[i - 1].ls_corr);
  1131.                 if (hit)
  1132.                     while (i > 0 &&
  1133.                         sp->lsis[i].ls_trans ==
  1134.                         sp->lsis[i - 1].ls_trans + 1 &&
  1135.                         sp->lsis[i].ls_corr ==
  1136.                         sp->lsis[i - 1].ls_corr + 1) {
  1137.                             ++hit;
  1138.                             --i;
  1139.                     }
  1140.             }
  1141.             corr = lp->ls_corr;
  1142.             break;
  1143.         }
  1144.     }
  1145.     days = *timep / SECSPERDAY;
  1146.     rem = *timep % SECSPERDAY;
  1147. #ifdef mc68k
  1148.     if (*timep == 0x80000000) {
  1149.         /*
  1150.         ** A 3B1 muffs the division on the most negative number.
  1151.         */
  1152.         days = -24855;
  1153.         rem = -11648;
  1154.     }
  1155. #endif /* defined mc68k */
  1156.     rem += (offset - corr);
  1157.     while (rem < 0) {
  1158.         rem += SECSPERDAY;
  1159.         --days;
  1160.     }
  1161.     while (rem >= SECSPERDAY) {
  1162.         rem -= SECSPERDAY;
  1163.         ++days;
  1164.     }
  1165.     tmp->tm_hour = (int) (rem / SECSPERHOUR);
  1166.     rem = rem % SECSPERHOUR;
  1167.     tmp->tm_min = (int) (rem / SECSPERMIN);
  1168.     /*
  1169.     ** A positive leap second requires a special
  1170.     ** representation.  This uses "... ??:59:60" et seq.
  1171.     */
  1172.     tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
  1173.     tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
  1174.     if (tmp->tm_wday < 0)
  1175.         tmp->tm_wday += DAYSPERWEEK;
  1176.     y = EPOCH_YEAR;
  1177. #define LEAPS_THRU_END_OF(y)    ((y) / 4 - (y) / 100 + (y) / 400)
  1178.     while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
  1179.         register int    newy;
  1180.  
  1181.         newy = y + days / DAYSPERNYEAR;
  1182.         if (days < 0)
  1183.             --newy;
  1184.         days -= (newy - y) * DAYSPERNYEAR +
  1185.             LEAPS_THRU_END_OF(newy - 1) -
  1186.             LEAPS_THRU_END_OF(y - 1);
  1187.         y = newy;
  1188.     }
  1189.     tmp->tm_year = y - TM_YEAR_BASE;
  1190.     tmp->tm_yday = (int) days;
  1191.     ip = mon_lengths[yleap];
  1192.     for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  1193.         days = days - (long) ip[tmp->tm_mon];
  1194.     tmp->tm_mday = (int) (days + 1);
  1195.     tmp->tm_isdst = 0;
  1196. #ifdef TM_GMTOFF
  1197.     tmp->TM_GMTOFF = offset;
  1198. #endif /* defined TM_GMTOFF */
  1199. }
  1200.  
  1201. char *
  1202. ctime(timep)
  1203. const time_t * const    timep;
  1204. {
  1205. /*
  1206. ** Section 4.12.3.2 of X3.159-1989 requires that
  1207. **    The ctime funciton converts the calendar time pointed to by timer
  1208. **    to local time in the form of a string.  It is equivalent to
  1209. **        asctime(localtime(timer))
  1210. */
  1211.     return asctime(localtime(timep));
  1212. }
  1213.  
  1214. /*
  1215. ** Adapted from code provided by Robert Elz, who writes:
  1216. **    The "best" way to do mktime I think is based on an idea of Bob
  1217. **    Kridle's (so its said...) from a long time ago.
  1218. **    [kridle@xinet.com as of 1996-01-16.]
  1219. **    It does a binary search of the time_t space.  Since time_t's are
  1220. **    just 32 bits, its a max of 32 iterations (even at 64 bits it
  1221. **    would still be very reasonable).
  1222. */
  1223.  
  1224. #ifndef WRONG
  1225. #define WRONG    (-1)
  1226. #endif /* !defined WRONG */
  1227.  
  1228. /*
  1229. ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
  1230. */
  1231.  
  1232. static int
  1233. increment_overflow(number, delta)
  1234. int *    number;
  1235. int    delta;
  1236. {
  1237.     int    number0;
  1238.  
  1239.     number0 = *number;
  1240.     *number += delta;
  1241.     return (*number < number0) != (delta < 0);
  1242. }
  1243.  
  1244. static int
  1245. normalize_overflow(tensptr, unitsptr, base)
  1246. int * const    tensptr;
  1247. int * const    unitsptr;
  1248. const int    base;
  1249. {
  1250.     register int    tensdelta;
  1251.  
  1252.     tensdelta = (*unitsptr >= 0) ?
  1253.         (*unitsptr / base) :
  1254.         (-1 - (-1 - *unitsptr) / base);
  1255.     *unitsptr -= tensdelta * base;
  1256.     return increment_overflow(tensptr, tensdelta);
  1257. }
  1258.  
  1259. static int
  1260. tmcomp(atmp, btmp)
  1261. register const struct tm * const atmp;
  1262. register const struct tm * const btmp;
  1263. {
  1264.     register int    result;
  1265.  
  1266.     if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  1267.         (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
  1268.         (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
  1269.         (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  1270.         (result = (atmp->tm_min - btmp->tm_min)) == 0)
  1271.             result = atmp->tm_sec - btmp->tm_sec;
  1272.     return result;
  1273. }
  1274.  
  1275. static time_t
  1276. time2(tmp, funcp, offset, okayp)
  1277. struct tm * const    tmp;
  1278. void (* const        funcp) P((const time_t*, long, struct tm*));
  1279. const long        offset;
  1280. int * const        okayp;
  1281. {
  1282.     register const struct state *    sp;
  1283.     register int            dir;
  1284.     register int            bits;
  1285.     register int            i, j ;
  1286.     register int            saved_seconds;
  1287.     time_t                newt;
  1288.     time_t                t;
  1289.     struct tm            yourtm, mytm;
  1290.  
  1291.     *okayp = FALSE;
  1292.     yourtm = *tmp;
  1293.     if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
  1294.         return WRONG;
  1295.     if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
  1296.         return WRONG;
  1297.     if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
  1298.         return WRONG;
  1299.     /*
  1300.     ** Turn yourtm.tm_year into an actual year number for now.
  1301.     ** It is converted back to an offset from TM_YEAR_BASE later.
  1302.     */
  1303.     if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
  1304.         return WRONG;
  1305.     while (yourtm.tm_mday <= 0) {
  1306.         if (increment_overflow(&yourtm.tm_year, -1))
  1307.             return WRONG;
  1308.         i = yourtm.tm_year + (1 < yourtm.tm_mon);
  1309.         yourtm.tm_mday += year_lengths[isleap(i)];
  1310.     }
  1311.     while (yourtm.tm_mday > DAYSPERLYEAR) {
  1312.         i = yourtm.tm_year + (1 < yourtm.tm_mon);
  1313.         yourtm.tm_mday -= year_lengths[isleap(i)];
  1314.         if (increment_overflow(&yourtm.tm_year, 1))
  1315.             return WRONG;
  1316.     }
  1317.     for ( ; ; ) {
  1318.         i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
  1319.         if (yourtm.tm_mday <= i)
  1320.             break;
  1321.         yourtm.tm_mday -= i;
  1322.         if (++yourtm.tm_mon >= MONSPERYEAR) {
  1323.             yourtm.tm_mon = 0;
  1324.             if (increment_overflow(&yourtm.tm_year, 1))
  1325.                 return WRONG;
  1326.         }
  1327.     }
  1328.     if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
  1329.         return WRONG;
  1330.     if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
  1331.         /*
  1332.         ** We can't set tm_sec to 0, because that might push the
  1333.         ** time below the minimum representable time.
  1334.         ** Set tm_sec to 59 instead.
  1335.         ** This assumes that the minimum representable time is
  1336.         ** not in the same minute that a leap second was deleted from,
  1337.         ** which is a safer assumption than using 58 would be.
  1338.         */
  1339.         if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
  1340.             return WRONG;
  1341.         saved_seconds = yourtm.tm_sec;
  1342.         yourtm.tm_sec = SECSPERMIN - 1;
  1343.     } else {
  1344.         saved_seconds = yourtm.tm_sec;
  1345.         yourtm.tm_sec = 0;
  1346.     }
  1347.     /*
  1348.     ** Divide the search space in half
  1349.     ** (this works whether time_t is signed or unsigned).
  1350.     */
  1351.     bits = TYPE_BIT(time_t) - 1;
  1352.     /*
  1353.     ** If time_t is signed, then 0 is just above the median,
  1354.     ** assuming two's complement arithmetic.
  1355.     ** If time_t is unsigned, then (1 << bits) is just above the median.
  1356.     */
  1357.     t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
  1358.     for ( ; ; ) {
  1359.         (*funcp)(&t, offset, &mytm);
  1360.         dir = tmcomp(&mytm, &yourtm);
  1361.         if (dir != 0) {
  1362.             if (bits-- < 0)
  1363.                 return WRONG;
  1364.             if (bits < 0)
  1365.                 --t; /* may be needed if new t is minimal */
  1366.             else if (dir > 0)
  1367.                 t -= ((time_t) 1) << bits;
  1368.             else    t += ((time_t) 1) << bits;
  1369.             continue;
  1370.         }
  1371.         if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
  1372.             break;
  1373.         /*
  1374.         ** Right time, wrong type.
  1375.         ** Hunt for right time, right type.
  1376.         ** It's okay to guess wrong since the guess
  1377.         ** gets checked.
  1378.         */
  1379.         /*
  1380.         ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
  1381.         */
  1382.         sp = (const struct state *)
  1383.             (((void *) funcp == (void *) localsub) ?
  1384.             lclptr : gmtptr);
  1385. #ifdef ALL_STATE
  1386.         if (sp == NULL)
  1387.             return WRONG;
  1388. #endif /* defined ALL_STATE */
  1389.         for (i = sp->typecnt - 1; i >= 0; --i) {
  1390.             if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
  1391.                 continue;
  1392.             for (j = sp->typecnt - 1; j >= 0; --j) {
  1393.                 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
  1394.                     continue;
  1395.                 newt = t + sp->ttis[j].tt_gmtoff -
  1396.                     sp->ttis[i].tt_gmtoff;
  1397.                 (*funcp)(&newt, offset, &mytm);
  1398.                 if (tmcomp(&mytm, &yourtm) != 0)
  1399.                     continue;
  1400.                 if (mytm.tm_isdst != yourtm.tm_isdst)
  1401.                     continue;
  1402.                 /*
  1403.                 ** We have a match.
  1404.                 */
  1405.                 t = newt;
  1406.                 goto label;
  1407.             }
  1408.         }
  1409.         return WRONG;
  1410.     }
  1411. label:
  1412.     newt = t + saved_seconds;
  1413.     if ((newt < t) != (saved_seconds < 0))
  1414.         return WRONG;
  1415.     t = newt;
  1416.     (*funcp)(&t, offset, tmp);
  1417.     *okayp = TRUE;
  1418.     return t;
  1419. }
  1420.  
  1421. static time_t
  1422. time1(tmp, funcp, offset)
  1423. struct tm * const    tmp;
  1424. void (* const        funcp) P((const time_t *, long, struct tm *));
  1425. const long        offset;
  1426. {
  1427.     register time_t            t;
  1428.     register const struct state *    sp;
  1429.     register int            samei, otheri;
  1430.     int                okay;
  1431.  
  1432.     if (tmp->tm_isdst > 1)
  1433.         tmp->tm_isdst = 1;
  1434.     t = time2(tmp, funcp, offset, &okay);
  1435. #ifdef PCTS
  1436.     /*
  1437.     ** PCTS code courtesy Grant Sullivan (grant@osf.org).
  1438.     */
  1439.     if (okay)
  1440.         return t;
  1441.     if (tmp->tm_isdst < 0)
  1442.         tmp->tm_isdst = 0;    /* reset to std and try again */
  1443. #endif /* defined PCTS */
  1444. #ifndef PCTS
  1445.     if (okay || tmp->tm_isdst < 0)
  1446.         return t;
  1447. #endif /* !defined PCTS */
  1448.     /*
  1449.     ** We're supposed to assume that somebody took a time of one type
  1450.     ** and did some math on it that yielded a "struct tm" that's bad.
  1451.     ** We try to divine the type they started from and adjust to the
  1452.     ** type they need.
  1453.     */
  1454.     /*
  1455.     ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
  1456.     */
  1457.     sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
  1458.         lclptr : gmtptr);
  1459. #ifdef ALL_STATE
  1460.     if (sp == NULL)
  1461.         return WRONG;
  1462. #endif /* defined ALL_STATE */
  1463.     for (samei = sp->typecnt - 1; samei >= 0; --samei) {
  1464.         if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
  1465.             continue;
  1466.         for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
  1467.             if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
  1468.                 continue;
  1469.             tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
  1470.                     sp->ttis[samei].tt_gmtoff;
  1471.             tmp->tm_isdst = !tmp->tm_isdst;
  1472.             t = time2(tmp, funcp, offset, &okay);
  1473.             if (okay)
  1474.                 return t;
  1475.             tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
  1476.                     sp->ttis[samei].tt_gmtoff;
  1477.             tmp->tm_isdst = !tmp->tm_isdst;
  1478.         }
  1479.     }
  1480.     return WRONG;
  1481. }
  1482.  
  1483. time_t
  1484. mktime(tmp)
  1485. struct tm * const    tmp;
  1486. {
  1487.     tzset();
  1488.     return time1(tmp, localsub, 0L);
  1489. }
  1490.  
  1491. #ifdef STD_INSPIRED
  1492.  
  1493. time_t
  1494. timelocal(tmp)
  1495. struct tm * const    tmp;
  1496. {
  1497.     tmp->tm_isdst = -1;    /* in case it wasn't initialized */
  1498.     return mktime(tmp);
  1499. }
  1500.  
  1501. time_t
  1502. timegm(tmp)
  1503. struct tm * const    tmp;
  1504. {
  1505.     tmp->tm_isdst = 0;
  1506.     return time1(tmp, gmtsub, 0L);
  1507. }
  1508.  
  1509. time_t
  1510. timeoff(tmp, offset)
  1511. struct tm * const    tmp;
  1512. const long        offset;
  1513. {
  1514.     tmp->tm_isdst = 0;
  1515.     return time1(tmp, gmtsub, offset);
  1516. }
  1517.  
  1518. #endif /* defined STD_INSPIRED */
  1519.  
  1520. #ifdef CMUCS
  1521.  
  1522. /*
  1523. ** The following is supplied for compatibility with
  1524. ** previous versions of the CMUCS runtime library.
  1525. */
  1526.  
  1527. long
  1528. gtime(tmp)
  1529. struct tm * const    tmp;
  1530. {
  1531.     const time_t    t = mktime(tmp);
  1532.  
  1533.     if (t == WRONG)
  1534.         return -1;
  1535.     return t;
  1536. }
  1537.  
  1538. #endif /* defined CMUCS */
  1539.  
  1540. /*
  1541. ** XXX--is the below the right way to conditionalize??
  1542. */
  1543.  
  1544. #ifdef STD_INSPIRED
  1545.  
  1546. /*
  1547. ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
  1548. ** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
  1549. ** is not the case if we are accounting for leap seconds.
  1550. ** So, we provide the following conversion routines for use
  1551. ** when exchanging timestamps with POSIX conforming systems.
  1552. */
  1553.  
  1554. static long
  1555. leapcorr(timep)
  1556. time_t *    timep;
  1557. {
  1558.     register struct state *        sp;
  1559.     register struct lsinfo *    lp;
  1560.     register int            i;
  1561.  
  1562.     sp = lclptr;
  1563.     i = sp->leapcnt;
  1564.     while (--i >= 0) {
  1565.         lp = &sp->lsis[i];
  1566.         if (*timep >= lp->ls_trans)
  1567.             return lp->ls_corr;
  1568.     }
  1569.     return 0;
  1570. }
  1571.  
  1572. time_t
  1573. time2posix(t)
  1574. time_t    t;
  1575. {
  1576.     tzset();
  1577.     return t - leapcorr(&t);
  1578. }
  1579.  
  1580. time_t
  1581. posix2time(t)
  1582. time_t    t;
  1583. {
  1584.     time_t    x;
  1585.     time_t    y;
  1586.  
  1587.     tzset();
  1588.     /*
  1589.     ** For a positive leap second hit, the result
  1590.     ** is not unique.  For a negative leap second
  1591.     ** hit, the corresponding time doesn't exist,
  1592.     ** so we return an adjacent second.
  1593.     */
  1594.     x = t + leapcorr(&t);
  1595.     y = x - leapcorr(&x);
  1596.     if (y < t) {
  1597.         do {
  1598.             x++;
  1599.             y = x - leapcorr(&x);
  1600.         } while (y < t);
  1601.         if (t != y)
  1602.             return x - 1;
  1603.     } else if (y > t) {
  1604.         do {
  1605.             --x;
  1606.             y = x - leapcorr(&x);
  1607.         } while (y > t);
  1608.         if (t != y)
  1609.             return x + 1;
  1610.     }
  1611.     return x;
  1612. }
  1613.  
  1614. #endif /* defined STD_INSPIRED */
  1615.